package com.zzj.controller;

import com.alibaba.fastjson2.JSON;
import com.zzj.annotation.LogAnnotation;
import com.zzj.base.Result;
import com.zzj.entity.File;
import com.zzj.entity.Folder;
import com.zzj.model.dto.folder.NewDto;
import com.zzj.model.dto.folder.RenameDto;
import com.zzj.model.dto.folder.SearchDto;
import com.zzj.model.dto.folder.ViewDto;
import com.zzj.service.IFileService;
import com.zzj.service.IFolderService;
import com.zzj.utils.FileUtil;
import io.swagger.v3.oas.annotations.Operation;
import jakarta.annotation.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;

import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.zip.ZipOutputStream;

/**
 * <p>
 * 文件夹表 前端控制器
 * </p>
 *
 * @author zzj
 * @since 2023-11-14
 */
@RestController
@RequestMapping("/folder")
public class FolderController {

    @Resource
    private IFolderService folderService;
    @Resource
    private IFileService fileService;

    @Resource
    private FileUtil fileUtil;

    @Transactional
    @LogAnnotation(name = "创建新文件夹", description = "创建文件夹")
    @Operation(summary = "创建文件夹", description = "创建文件夹", tags = {"Folder"})
    @PostMapping("/newFolder")
    public Result<?> newFolder(@RequestBody @Validated NewDto in) {
        boolean b = folderService.checkParentValid(in.getCreatorId(), in.getPathName(), in.getParentId());
        if (!b) {
            return Result.error("路径错误");
        }
        b = folderService.checkExist(in.getCreatorId(), in.getPathName(), in.getParentId());
        if (b) {
            return Result.error("文件夹名称已存在");
        }
        Folder newFolder = folderService.create(in.getCreatorId(), in.getPathName(), in.getParentId());
        if (newFolder != null) {
            return Result.success("创建成功", newFolder);
        }
        return Result.error();
    }

    @Transactional
    @LogAnnotation(name = "查看文件下所有文件夹、文件", description = "查看文件下所有文件夹、文件")
    @Operation(summary = "查看文件下所有文件夹、文件", description = "查看文件下所有文件夹、文件", tags = {"Folder"})
    @PostMapping("/view")
    public Result<?> view(@RequestBody @Validated ViewDto in) {
        in.setPathName(in.getPathName() + "tmp");
        boolean b = folderService.checkParentValid(in.getCreatorId(), in.getPathName(), in.getParentId());
        if (!b) {
            return Result.error("路径错误");
        }
        List<Folder> folders = folderService.queryList(in.getCreatorId(), in.getParentId());
        List<File> files = fileService.queryList(in.getCreatorId(), in.getParentId());
        Map<String, Object> map = new HashMap<>();
        map.put("folders", folders);
        map.put("files", files);
        return Result.success("查询成功", map);
    }

    @Transactional
    @LogAnnotation(name = "文件夹下关键字搜索文件夹、文件", description = "文件夹下关键字搜索文件夹、文件")
    @Operation(summary = "文件夹下关键字搜索文件夹、文件", description = "文件夹下关键字搜索文件夹、文件", tags = {"Folder"})
    @PostMapping("/search")
    public Result<?> search(@RequestBody @Validated SearchDto in) {
        List<Folder> folders = folderService.queryList(in.getCreatorId(), in.getParentId(), in.getSearchKey());
        List<File> files = fileService.queryList(in.getCreatorId(), in.getParentId(), in.getSearchKey());
        Map<String, Object> map = new HashMap<>();
        map.put("folders", folders);
        map.put("files", files);
        return Result.success("查询成功", map);
    }

    @Transactional
    @LogAnnotation(name = "删除文件夹", description = "删除文件夹")
    @Operation(summary = "删除文件夹", description = "删除文件夹", tags = {"Folder"})
    @PostMapping("/remove")
    public Result<?> remove(@RequestParam("id") String id) {
        //首先删除文件件下的所有文件
        boolean b = fileService.removes(id);
        if (b) {
            //删除文件夹
            b = folderService.removeById(id);
            if (b) {
                return Result.success("删除成功");
            }
        }
        return Result.error("删除失败");
    }

    @Transactional
    @LogAnnotation(name = "重命名文件夹", description = "重命名文件夹")
    @Operation(summary = "重命名文件夹", description = "重命名文件夹", tags = {"Folder"})
    @PostMapping("/rename")
    public Result<?> rename(@RequestBody @Validated RenameDto in) {
        boolean b = folderService.updateName(in.getId(), in.getParentId(), in.getNewName());
        if (b) {
            return Result.success("重命名成功");
        }
        return Result.error("重命名失败");
    }

    void copyFolderAllFile(String pathName, String parentId) {
        List<Folder> folderList = folderService.getFolderList(parentId);
        for (Folder folder : folderList) {
            fileUtil.getFolder(pathName + '/' + folder.getName());
            copyFolderAllFile(pathName + '/' + folder.getName(), String.valueOf(folder.getId()));
        }
        fileService.getFileList(parentId).forEach(file -> {
            fileUtil.copyFile(file.getPath(), pathName,file.getName());
        });
    }

    @Transactional
    @LogAnnotation(name = "下载文件夹", description = "下载文件夹")
    @Operation(summary = "下载文件夹", description = "下载文件夹", tags = {"Folder"})
    @GetMapping("/download")
    public ResponseEntity<StreamingResponseBody> download(@RequestParam("id") String id) {
        fileUtil.removeFolder("/tmp");
        Folder one = folderService.getById(id);
        if (one == null) {
            return ResponseEntity.ok()
                    .headers(new HttpHeaders())
                    .body(responseBody -> responseBody.write(JSON.toJSONString(Result.error("数据库找不到该文件夹")).getBytes(StandardCharsets.UTF_8)));
        }
        String pathName = "/tmp/" + UUID.randomUUID() + "/" + one.getName();
        copyFolderAllFile(pathName, id);

        java.io.File folder = fileUtil.getFolder(pathName);

        // 设置响应头
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
        headers.setContentDispositionFormData("attachment", URLEncoder.encode(folder.getName() + ".zip", StandardCharsets.UTF_8));

        // 构造StreamingResponseBody
        StreamingResponseBody responseBody = outputStream -> {
            // 使用ZipOutputStream将文件夹内容写入响应输出流
            // 这里可以根据需要实现自定义的文件夹打包逻辑
            // 这里简单示例使用了ZipOutputStream，具体实现可能需要根据需求进行调整
            // 注意：这里没有关闭 ZipOutputStream，需要在完成写入后手动关闭
            // 或者使用 try-with-resources 语法确保资源被正确关闭
            // 如果文件较大，可能需要考虑分批读取和写入
            try (ZipOutputStream zipOutputStream = new ZipOutputStream(outputStream)) {
                fileUtil.folderToZip(folder, folder.getName(), zipOutputStream);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        };
        // 返回ResponseEntity，包含StreamingResponseBody和响应头
        return new ResponseEntity<>(responseBody, headers, HttpStatus.OK);
    }

    @Transactional
    @LogAnnotation(name = "Test", description = "Test")
    @Operation(summary = "Test", description = "Test", tags = {"Folder"})
    @PostMapping("/test")
    public Result<?> test() {

        return Result.success();
    }


}
